package com.linkoog.devtools.open_in_explorer;

import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessIOExecutorService;
import com.intellij.execution.util.ExecUtil;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.lightEdit.LightEditCompatible;
import com.intellij.idea.ActionsBundle;
import com.intellij.jna.JnaLoader;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.NlsActions.ActionText;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import com.linkoog.devtools.utils.ExplorerHolder;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Ole32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * This helpful action opens a file or directory in a system file manager.
 */
public class RevealFileAction extends DumbAwareAction implements LightEditCompatible {
    private static final Logger LOG = Logger.getInstance(RevealFileAction.class);

    public static final NotificationListener FILE_SELECTING_LISTENER = new NotificationListener.Adapter() {
        @Override
        protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
        var url = e.getURL();
        if (url != null) {
            try {
                ExplorerHolder.openFile(Path.of(url.toURI()));
            }
            catch (InvalidPathException | URISyntaxException ex) {
                LOG.warn("invalid URL: " + url, ex);
            }
        }
        notification.hideBalloon();
        }
    };

    public RevealFileAction() {
        getTemplatePresentation().setText(getActionName(null));
    }

    @Override
    public void update(@NotNull AnActionEvent e) {
        Editor editor = e.getData(CommonDataKeys.EDITOR);
        e.getPresentation().setEnabled(isSupported() && findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE)) != null &&
                (!ActionPlaces.isPopupPlace(e.getPlace()) ||
                        editor == null ||
                        !editor.getSelectionModel().hasSelection() ||
                        EditorUtil.contextMenuInvokedOutsideOfSelection(e)));
        e.getPresentation().setText(getActionName(e.getPlace()));
    }

    @Override
    public @NotNull ActionUpdateThread getActionUpdateThread() {
        return ActionUpdateThread.BGT;
    }

    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        var file = findLocalFile(e.getData(CommonDataKeys.VIRTUAL_FILE));
        if (file != null) {
            ExplorerHolder.openFile(file.toNioPath());
        }
    }

    public static boolean isSupported() {
        return SystemInfo.isWindows || SystemInfo.isMac || SystemInfo.hasXdgOpen() ||
                Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN);
    }

    public static @ActionText @NotNull String getActionName() {
        return getActionName(null);
    }

    public static @ActionText @NotNull String getActionName(@Nullable String place) {
        if (ActionPlaces.EDITOR_TAB_POPUP.equals(place) || ActionPlaces.EDITOR_POPUP.equals(place) || ActionPlaces.PROJECT_VIEW_POPUP.equals(place)) {
            return getFileManagerName();
        }
        else if (SystemInfo.isMac) {
            return ActionsBundle.message("action.RevealIn.name.mac");
        }
        else {
            return ActionsBundle.message("action.RevealIn.name.other", getFileManagerName());
        }
    }

    public static @NotNull @ActionText String getFileManagerName() {
        return SystemInfo.isMac ? IdeBundle.message("action.finder.text") :
                SystemInfo.isWindows ? IdeBundle.message("action.explorer.text") :
                        Objects.requireNonNullElseGet(ExplorerHolder.fileManagerName, () -> IdeBundle.message("action.file.manager.text"));
    }

    public static @Nullable VirtualFile findLocalFile(@Nullable VirtualFile file) {
        if (file == null) return null;
        if (file.isInLocalFileSystem()) return file;

        var fs = file.getFileSystem();
        if (fs instanceof ArchiveFileSystem && file.getParent() == null) {
            return ((ArchiveFileSystem)fs).getLocalByEntry(file);
        }

        return null;
    }


}

